package com.apes.scm.settle.payment.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.util.Arith;
import com.apes.framework.util.MapUtil;
import com.apes.hr.base.repository.WorkPostGroupRepository;
import com.apes.scm.account.ledger.service.LedgerService;
import com.apes.scm.income.model.Income;
import com.apes.scm.income.model.IncomeItem;
import com.apes.scm.income.repository.IncomeItemRepository;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.finance.model.IncomeType;
import com.apes.scm.masterdata.finance.repository.IncomeTypeRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.repository.DeptRepository;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.settle.payment.model.SupplierIncomePay;
import com.apes.scm.settle.payment.model.SupplierIncomePayItem;
import com.apes.scm.settle.payment.model.SupplierIncomePayMethod;
import com.apes.scm.settle.payment.repository.SupplierIncomePayRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 供应商收入收款单服务
 *
 * @author wuq
 * @create 2018-11-02 17:25
 */
@Service
public class SupplierIncomePayService extends DomainService {

    @Autowired
    private SupplierIncomePayRepository supplierIncomePayRepository;
    @Autowired
    private LedgerService ledgerService;
    @Autowired
    private IncomeItemRepository incomeItemRepository;


    public SupplierIncomePay create(SimpleRequest request) {
        SupplierIncomePay payment = request.getO(SupplierIncomePay.class);
        payment.setState("sent");
        payment.getSupplierIncomePayItems().removeIf(paymentItem -> paymentItem.getAmount() == 0);
        if (payment.getSupplierIncomePayItems().size() == 0) throw new RuntimeException("单据明细有误，本次扣款金额不能全部为0 或者不存在！");

        payment.computeAmt();

        // 更新供应商收入单，冻结金额增加
        payment.getSupplierIncomePayItems().forEach(supplierIncomePayItem -> {
            IncomeItem incomeItem = incomeItemRepository.findOne(supplierIncomePayItem.getIncomeItemId());
            incomeItem.changeFreezeAmount(supplierIncomePayItem.getAmount());
            incomeItemRepository.saveAndFlush(incomeItem);
        });
        return supplierIncomePayRepository.saveAndFlush(payment);
    }

    public void checkData(SimpleRequest request) {
        String id = request.get("id");
        int version = request.get("version");

        // 从数据库中取数，检查数据
        SupplierIncomePay oldPayment = supplierIncomePayRepository.findOne(id);
        if (oldPayment == null) throw new RuntimeException("付款单【" + id + "】在系统中不存在。");
        if (oldPayment.getVersion() != version) throw new RuntimeException("记录已更新或已删除，请重新提交！");
    }


    /**
     * 更新采购付款单
     * 更新时：先将之前的冻结的数据还原，然后写入新的数据
     *
     * @param request
     * @return
     */
    public SupplierIncomePay update(SimpleRequest request) {
        checkData(request); // 检查数据
        SupplierIncomePay payment = request.getO(SupplierIncomePay.class);
        payment.getSupplierIncomePayItems().removeIf(paymentItem -> paymentItem.getAmount() == 0);

        if (payment.getSupplierIncomePayItems().size() == 0) throw new RuntimeException("单据明细有误，本次扣款金额不能全部为0 或者不存在！");

        // 还原之前的冻结数
        SupplierIncomePay oldPayment = supplierIncomePayRepository.findOne(payment.getId());
        oldPayment.getSupplierIncomePayItems().forEach(supplierIncomePayItem -> {
            IncomeItem incomeItem = incomeItemRepository.findOne(supplierIncomePayItem.getIncomeItemId());
            incomeItem.changeFreezeAmount(-1 * supplierIncomePayItem.getAmount());
            incomeItemRepository.saveAndFlush(incomeItem);
        });

        // 更新供应商收入单，冻结金额增加
        payment.getSupplierIncomePayItems().forEach(supplierIncomePayItem -> {
            IncomeItem incomeItem = incomeItemRepository.findOne(supplierIncomePayItem.getIncomeItemId());
            incomeItem.changeFreezeAmount(supplierIncomePayItem.getAmount());
            incomeItemRepository.saveAndFlush(incomeItem);
        });

        payment.computeAmt();
        return supplierIncomePayRepository.saveAndFlush(payment);
    }

    public String delete(SimpleRequest request) {
        checkData(request); // 检查数据
        SupplierIncomePay payment = request.getO(SupplierIncomePay.class);

        payment.getSupplierIncomePayItems().forEach(supplierIncomePayItem -> {
            IncomeItem incomeItem = incomeItemRepository.findOne(supplierIncomePayItem.getIncomeItemId());
            incomeItem.changeFreezeAmount(-1 * supplierIncomePayItem.getAmount());
            incomeItemRepository.saveAndFlush(incomeItem);
        });

        payment.setState("delete");
        payment.setDeleteDate(new Date());
        payment.setDeleteUID(getPerson(request));
        supplierIncomePayRepository.saveAndFlush(payment);
        return "删除成功！";
    }

    /**
     * 审核操作
     *
     * @param request
     * @return
     */
    public SupplierIncomePay approve(SimpleRequest request) {
        checkData(request); // 检查数据
        SupplierIncomePay payment = request.getO(SupplierIncomePay.class);

        payment.getSupplierIncomePayItems().forEach(supplierIncomePayItem -> {
            IncomeItem incomeItem = incomeItemRepository.findOne(supplierIncomePayItem.getIncomeItemId());
            incomeItem.changeFreezeAmount(-1 * supplierIncomePayItem.getAmount());
            incomeItem.changeRecoveryAmount(supplierIncomePayItem.getAmount());     //  增加已收金额
            incomeItemRepository.saveAndFlush(incomeItem);
        });

        // 返利：未清项 减少，返利：冻结项 增加
        Map<String, Object> paramMap = MapUtil.mapper("company", payment.getCompany(), "partner", payment.getPartner());
        ledgerService.transaction(paramMap, payment.getId(), payment.getInnerBusinessType(), new Date(),
                "discount_unsettled", "discount_freeze", payment.getAmount());

        payment.setState("approve");
        payment.setApproveDate(new Date());
        payment.setApproveUID(getPerson(request));
        payment = supplierIncomePayRepository.saveAndFlush(payment);

        return payment;
    }

    public SupplierIncomePay pay(SimpleRequest request) {
        SupplierIncomePay payment = request.getO(SupplierIncomePay.class);

        // 检查 费用明细
        double methodAmount = payment.getSupplierIncomePayMethodSet().stream().mapToDouble(SupplierIncomePayMethod::getAmount).sum();
        if (Math.abs(Arith.round(payment.getAmount() - methodAmount, 2)) > 0.01) {
            throw new RuntimeException("付款总额与扣款总金额不一致，请检查！");
        }

        Map<String, Object> paramMap = MapUtil.mapper("company", payment.getCompany(), "partner", payment.getPartner());
        ledgerService.transaction(paramMap, payment.getId(), payment.getInnerBusinessType(), new Date(),
                "discount_freeze", "discount_settled", payment.getAmount());

        payment.setState("pay");
        payment.setApproveDate(new Date());
        payment.setApproveUID(getPerson(request));
        payment = supplierIncomePayRepository.saveAndFlush(payment);

        return payment;
    }


    public Page<Map<String, Object>> findIncome(SimpleRequest request) {
        JSONObject json = request.getJO();

        // 获取供应商编码
        JSONObject conditionModel = json.getJSONObject("conditionModel");
        Optional.ofNullable(conditionModel).orElseThrow(() -> new RuntimeException("查询费用明细传入条件有误，请检查"));

        JSONObject partnerJson = conditionModel.getJSONObject("partner");
        Optional.ofNullable(partnerJson).orElseThrow(() -> new RuntimeException("查询费用明细没有供应商条件，请检查"));

        JSONObject companyJson = conditionModel.getJSONObject("company");
        Optional.ofNullable(companyJson).orElseThrow(() -> new RuntimeException("查询费用明细没有公司条件，请检查"));

        // 获取输入条件
        JSONArray condition = json.getJSONArray("condition");
        Date approveStartDate = new Date();
        Date approveEndDate = new Date();

        for (int i = 0, len = condition.size(); i < len; i++) {
            JSONObject tempJson = condition.getJSONObject(i);
            if (Objects.equals("LTE", tempJson.getString("operator"))) {
                approveEndDate = tempJson.getDate("value");
            }

            if (Objects.equals("GTE", tempJson.getString("operator"))) {
                approveStartDate = tempJson.getDate("value");
            }
        }

        int page = Integer.valueOf(request.get("page").toString()) + 1;
        int number = page - 1;
        return incomeItemRepository.findAllForSupplierIncomePay(partnerJson.getString("id"), companyJson.getString("id"), approveStartDate, approveEndDate,
                PageRequest.of(number, request.get("size")));
    }


    // 导入
    public Map importLogic(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        // 数据校验 判断前端明细是否有数据
        JSONObject modelJson = getJO.getJSONObject("model");
        if (modelJson.getJSONArray("paymentIncomeSet").isEmpty()) throw new RuntimeException("没有费用明细数据");

        // 数据匹配
        compare(modelJson.getJSONArray("paymentIncomeSet"), getJO.getJSONObject("importData"));

        return MapUtil.mapper("items", modelJson.getJSONArray("paymentIncomeSet"), "msg", "");
    }

    private void compare(JSONArray modelItems, JSONObject importData) {
        modelItems.forEach(itemJson -> {
            JSONObject modelJson = ((JSONObject) itemJson);

            importData.forEach((sheetName, excelItems) -> {
                JSONArray importDataValueArray = (JSONArray) excelItems;
                importDataValueArray.forEach(excelItemData -> {
                    JSONArray excelItem = (JSONArray) excelItemData;
                    String incomeId = excelItem.get(1).toString();
                    String incomeItemId = excelItem.get(2).toString();
                    // 核心判断逻辑
                    if (modelJson.getString("incomeId").equals(incomeId) && modelJson.getString("incomeItemId").substring(7, 13).equals(incomeItemId)
                            && modelJson.getInteger("incomeAmount").equals(excelItem.get(7))) {
                        if (excelItem.size() < 8) throw new RuntimeException("本次扣款金额不能为空");
                        modelJson.put("import", true);
                    }
                });
            });

        });
    }

    public Map incomePayImportLogic(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        // 数据匹配
        // 数据校验 判断前端明细是否有数据
        JSONObject modelJson = getJO.getJSONObject("model");
        // 数据匹配
        List maps = builderResultList(getJO.getJSONObject("importData"));

        return MapUtil.mapper("items", maps, "msg", "");
    }

    private List builderResultList(JSONObject importData) {
        List resultList = new ArrayList<>();
        importData.forEach((sheetName, excelItems) -> {
            JSONArray importDataValueArray = (JSONArray) excelItems;
            importDataValueArray.forEach(excelItem -> {
                if (((JSONArray) excelItem).get(1).equals("收入类型")) return;
                List<IncomeType> incomeTypes = SpringManager.getBean(IncomeTypeRepository.class).findAll(JpaDsl.toCriteriaByEq("name", ((JSONArray) excelItem).get(1).toString()));
                List<Enumeration> enumerations = SpringManager.getBean(EnumerationRepository.class).findAll(JpaDsl.toCriteriaByEq("description", ((JSONArray) excelItem).get(4).toString()));
                if (incomeTypes.size() < 1 || enumerations.size() < 1) throw new RuntimeException("导入不需要序号或者收入类型/收入类别无法找到，请确认！");
                resultList.add(MapUtil.mapper("incomeType", incomeTypes.get(0),
                        "incomeId", ((JSONArray) excelItem).get(2).toString(),
                        "incomeItemId", ((JSONArray) excelItem).get(3).toString(),
                        "inComeCategory", enumerations.get(0),
                        "needIncomeAmount",   ((JSONArray) excelItem).size() > 5 && ((JSONArray) excelItem).get(5) != null ? ((JSONArray) excelItem).get(5).toString() : 0,
                        "incomeAmount", ((JSONArray) excelItem).size() > 6 && ((JSONArray) excelItem).get(6) != null ? ((JSONArray) excelItem).get(6).toString() : 0,
                        "recoveryAmount", ((JSONArray) excelItem).size() > 7 && ((JSONArray) excelItem).get(7) != null ? ((JSONArray) excelItem).get(7).toString() : 0,
                        "freezeAmount",((JSONArray) excelItem).size() > 8 && ((JSONArray) excelItem).get(8) != null ? ((JSONArray) excelItem).get(8).toString() : 0,
                        "amount", ((JSONArray) excelItem).size() > 9 && ((JSONArray) excelItem).get(9) != null ? ((JSONArray) excelItem).get(9).toString() : 0,
                        "startDate",  ((JSONArray) excelItem).size() > 10 && ((JSONArray) excelItem).get(10) != null ? ((JSONArray) excelItem).get(10).toString() : null,
                        "endDate", ((JSONArray) excelItem).size() > 11 && ((JSONArray) excelItem).get(11) != null ? ((JSONArray) excelItem).get(11).toString() : null
                ));
            });
        });
        return resultList;
    }

}
